package Tar

import (
	"archive/tar"
	"io"
	"os"
	"path/filepath"
)

// createTarFile
// 说明：创建一个tar文件，包含指定目录下的所有文件和子目录
func createTarFile(dirPath, tarFilePath string) error {
	// 创建tar文件
	tarFile, err := os.Create(tarFilePath)
	if err != nil {
		return err
	}
	defer tarFile.Close()

	// 创建tar writer
	tw := tar.NewWriter(tarFile)
	defer tw.Close()

	// 遍历目录并添加文件到tar文件中
	return filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// 创建tar header
		header, err := tar.FileInfoHeader(info, info.Name())
		if err != nil {
			return err
		}

		// 调整header的Name字段，使其相对于给定目录的路径（例如：如果dirPath是"/a"，而当前文件是"/a/b/c"，则header.Name应为"b/c"）
		header.Name, err = filepath.Rel(dirPath, path)
		if err != nil {
			return err
		}

		// 写入header
		if err := tw.WriteHeader(header); err != nil {
			return err
		}

		// 如果不是目录，则写入文件内容
		if !info.Mode().IsDir() {
			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()
			_, err = io.Copy(tw, file) // 将文件内容复制到tar writer中
			return err
		}
		return nil
	})
}

// extractTarFile
// 说明：将一个tar文件解压到一个特定的目录
func extractTarFile(tarPath, destPath string) error {
	// 打开tar文件
	tarFile, err := os.Open(tarPath)
	if err != nil {
		return err
	}
	defer tarFile.Close()

	// 创建一个tar.Reader来读取tar文件
	tarReader := tar.NewReader(tarFile)

	// 遍历tar文件中的所有文件和目录
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break // 没有更多文件了
		}
		if err != nil {
			return err
		}

		// 构建目标文件的完整路径
		targetPath := filepath.Join(destPath, header.Name)

		switch header.Typeflag {
		case tar.TypeDir:
			// 如果是目录，则创建目录
			if err := os.MkdirAll(targetPath, 0755); err != nil {
				return err
			}
		case tar.TypeReg:
			// 如果是文件，则创建文件并写入内容
			file, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err := io.Copy(file, tarReader); err != nil {
				file.Close()
				return err
			}
			file.Close()
		}
	}

	return nil
}

// readTarHeader
// 说明：读取tar中的文件列表名称
// 注意：文件列表包含表示当前目录的.
func readTarHeader(tarFilePath string) ([]*tar.Header, error) {
	// 打开tar文件
	file, err := os.Open(tarFilePath)
	if err != nil {
		return nil, err
	}
	defer file.Close() // 确保在函数结束时关闭文件

	// 创建tar读取器
	tr := tar.NewReader(file)

	list := make([]*tar.Header, 0)
	// 遍历tar文件中的所有条目
	for {
		header, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				// io.EOF表示已到达文件末尾，没有更多的条目了
				break
			}
			return nil, err
		}

		// header.Name包含了文件的路径和名称
		list = append(list, header)
	}

	return list, nil
}

func readTarContent(tarFilePath string, fileName string) ([]byte, error) {
	fileNames := make(map[string][]byte)
	fileNames[fileName] = nil

	err := readTarContents(tarFilePath, fileNames)
	if err != nil {
		return nil, err
	}

	if fileNames[fileName] == nil {
		return nil, err
	}

	return fileNames[fileName], nil
}

func readTarContents(tarFilePath string, fileNames map[string][]byte) error {
	// 打开tar文件
	tarFile, err := os.Open(tarFilePath)
	if err != nil {
		return err
	}
	defer tarFile.Close()

	// 创建一个tar读取器
	tarReader := tar.NewReader(tarFile)

	// 循环读取tar文件中的每个条目
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			// 如果读取到EOF，则结束循环
			break
		}
		if err != nil {
			return err
		}

		// 检查文件名是否是你想要的文件名
		_, ok := fileNames[header.Name]
		if ok {
			// 读取文件内容
			content, err := io.ReadAll(tarReader)

			if err != nil {
				return err
			} else {
				fileNames[header.Name] = content
			}
		}
	}

	return nil
}
